package com.fowo.api.sys.rd2.interceptor;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.fowo.api.common.annotaion.DataObjectType;
import com.fowo.api.common.model.PageSearch;
import com.fowo.api.common.util.ContextHolder;
import com.fowo.api.sys.rd2.RoleData2FilterService;
import com.fowo.api.user.model.JwtUserInfo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * 基于新的角色模块权限的过滤支持
 * @author yl_ls
 */
@Slf4j
public class RoleData2Interceptor extends JsqlParserSupport implements InnerInterceptor {
    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        JwtUserInfo jwtUserInfo = JwtUserInfo.fromHeader();
        if (jwtUserInfo == null || jwtUserInfo.getUserId() == null || jwtUserInfo.getUserId() <= 0) {
            // 系统内部任务调用，或未登录或无效的用户编号
            return;
        }
        PageSearch searchParam = getSearchParam(parameter);
        if (searchParam != null && searchParam.isDisableDataPremissions()) {
            // 禁用了数据权限
            return;
        }

        RoleData2Metadata metadata = getMetadata(ms, searchParam);
        if (metadata == null || metadata.pass) {
            return;
        }

        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        mpBs.sql(parserSingle(mpBs.sql(), new HandleContext(metadata, jwtUserInfo.getUserId())));
    }

    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        HandleContext context = (HandleContext)obj;

        if (select.getSelectBody() instanceof PlainSelect) {
            processPlainSelect((PlainSelect)select.getSelectBody(), context);
        }
    }

    private void processPlainSelect(PlainSelect plainSelect, HandleContext context) {
        if(context.currentUserId == null) {
            return;
        }

        RoleData2FilterService filterService = ContextHolder.getApplicationContext().getBean(RoleData2FilterService.class);
        filterService.applyFilter(plainSelect, context.currentUserId, context.metadata.dataObjectType);
    }

    private static final ThreadLocal<Map<String, RoleData2Metadata>> META_DATA_LOCAL = new ThreadLocal<>();

    // 尝试获取相关元数据
    private RoleData2Metadata getMetadata(MappedStatement ms, PageSearch searchParam) {
        Map<String, RoleData2Metadata> stringRoleData2MetadataMap = META_DATA_LOCAL.get();
        if (stringRoleData2MetadataMap != null && stringRoleData2MetadataMap.containsKey(ms.getId())) {
            return stringRoleData2MetadataMap.get(ms.getId());
        }

        RoleData2FilterService filterService = ContextHolder.getApplicationContext().getBean(RoleData2FilterService.class);

        RoleData2Metadata metadata = new RoleData2Metadata();
        if (searchParam != null) {
            DataObjectType dataObjectType = searchParam.getClass().getAnnotation(DataObjectType.class);
            if (dataObjectType != null) {
                metadata.dataObjectType = dataObjectType.value();
                metadata.pass = filterService.supportForObject(metadata.dataObjectType) == null;
            }
        }
        if (metadata.dataObjectType == null) {
            log.warn("无法找到 Mapper " + ms.getId() + " 的关联对象类型，数据权限过滤处理失败！");
            metadata.pass = true;
        }
        if (stringRoleData2MetadataMap == null) {
            stringRoleData2MetadataMap = new HashMap<>();
            META_DATA_LOCAL.set(stringRoleData2MetadataMap);
        }
        stringRoleData2MetadataMap.put(ms.getId(), metadata);
        return metadata;
    }

    // 尝试从参数中找到 PageSearch 实例
    @SuppressWarnings({"unchecked", "rawtypes"})
    private PageSearch getSearchParam(Object parameter) {
        if (parameter != null && Map.class.isAssignableFrom(parameter.getClass())) {
            final Optional<Object> optional = ((Map) parameter).values().stream().filter(p -> p != null && PageSearch.class.isAssignableFrom(p.getClass())).findFirst();
            if (optional.isPresent()) {
                return (PageSearch)optional.get();
            }
        }
        return null;
    }

    @AllArgsConstructor
    static class HandleContext {
        RoleData2Metadata metadata;
        Long currentUserId;
    }

    static class RoleData2Metadata {
        /**
         * 是否不需要添加过滤
         */
        boolean pass;
        /**
         * 关联实体类型
         */
        Class<?> dataObjectType;
    }
}
